<template>
  <view
    id="calendar" class="calendar" :style="{
      '--calendar-width': `${calendarWidth}px`,
    }"
  >
    <view class="calendar-header">
      <view class="col-l" @click="prevMonth">
        <IconMore />
      </view>
      <text class="month">{{ currentMonth.format('YYYY-MM') }}</text>
      <view class="col-r" @click="nextMonth">
        <IconMore :is-right="true" />
      </view>
    </view>
    <view class="calendar-week">
      <view
        v-for="(w, i) in weeks" :key="i" class="week-item"
      >
        {{ w }}
      </view>
    </view>
    <view class="calendar-body">
      <view
        v-for="(day, index) in days"
        :key="index"
        :class="[dayClass(day), day.isFuture && 'future']"
      >
        <text>{{ day.dayNumber }}</text>
        <view v-if="activeDays.includes(day.dayNumber)" class="dot" />
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import dayjs from 'dayjs'
import { getRect } from '@/utils/systemInfo'
import IconMore from './IconMore.vue'
// #region Props
withDefaults(defineProps<{ activeDays: number[] }>(), { activeDays: () => ([]) })
// #endregion
// #region Emits
const emit = defineEmits(['dateChange', 'select'])

const calendarWidth = ref(375)

const today = dayjs()
const oneMonth = today.add(-1, 'month')
const threeMonth = today.add(-2, 'month')

const currentMonth = ref(today) // 当前月份
const selectedRange = ref([null, null]) // 范围选择
const weeks = ['日', '一', '二', '三', '四', '五', '六']

// #endregion
// #region Hooks
// #endregion
// #region Computed
// #endregion
// #region Watch
// #endregion
// #region Event
// #endregion
// #region Function
// 构造日期网格
const days = computed(() => {
  const startOfMonth = currentMonth.value.startOf('month')
  const endOfMonth = currentMonth.value.endOf('month')
  const startWeek = startOfMonth.day()
  const totalDays = endOfMonth.date()
  const grid = []

  // 上个月占位
  for (let i = 0; i < startWeek; i++) {
    grid.push({ empty: true })
  }

  // 当前月日期
  for (let d = 1; d <= totalDays; d++) {
    const date = currentMonth.value.date(d)
    grid.push({
      date,
      dayNumber: d,
      isToday: date.isSame(today, 'day'),
      isFuture: date.isAfter(today, 'day'),
      hasDot: [8, 9, 12, 13].includes(d), // 模拟有事件的日期
    })
  }

  return grid
})

// 日期样式
function dayClass(day) {
  if (day.empty)
    return 'day-item empty'
  const [start, end] = selectedRange.value
  const inRange
    = start && end && day.date.isAfter(start) && day.date.isBefore(end)
  const isStart = start && day.date.isSame(start, 'day')
  const isEnd = end && day.date.isSame(end, 'day')

  return [
    'day-item',
    {
      today: day.isToday,
      selected: isStart || isEnd,
      inRange,
    },
  ]
}

// 切换月份
function prevMonth() {
  if (threeMonth.isAfter(currentMonth.value)) {
    return uni.showToast({
      title: '仅支持查询最近3个月的记录',
      icon: 'none',
    })
  }

  currentMonth.value = currentMonth.value.subtract(1, 'month')
  emit('dateChange', currentMonth.value)
}
function nextMonth() {
  if (oneMonth.isBefore(currentMonth.value)) {
    return uni.showToast({
      title: '仅支持查询最近3个月的记录',
      icon: 'none',
    })
  }
  currentMonth.value = currentMonth.value.add(1, 'month')
  emit('dateChange', currentMonth.value)
}

// 点击日期选择范围
function selectDate(day) {
  if (day.empty)
    return
  const [start, end] = selectedRange.value
  if (!start || (start && end)) {
    selectedRange.value = [day.date, null]
  }
  else if (day.date.isBefore(start)) {
    selectedRange.value = [day.date, start]
  }
  else {
    selectedRange.value = [start, day.date]
  }
}
// #endregion
// #region Life Cycle
onReady(async () => {
  const instance = getCurrentInstance().proxy

  const info: any = await getRect('.calendar', instance)
  if (info.width) {
    calendarWidth.value = info.width
  }
})
// #endregion
// #region Expose
// #endregion
</script>

<style scoped lang="scss">
.calendar {
  background: var(--card-border-color);
  text-align: center;
  width: 100%;
  --calendar-width: 375px;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
  margin: 10px;
  font-size: 18px;
  .col-l,
  .col-r {
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
  }
}

.month {
  font-size: 17px;
}

.calendar-week {
  display: grid;
  grid-template-columns: repeat(7, 0fr);
  column-gap: 10px;
  font-size: 13px;
  color: var(--text-color);
  opacity: 0.5;
  margin-bottom: 5px;
  margin: 0 auto;
  .week-item {
    width: calc((var(--calendar-width) - 60px) / 7);
    height: calc((var(--calendar-width) - 60px) / 7);
    line-height: calc((var(--calendar-width) - 60px) / 7);
  }
}

.calendar-body {
  display: grid;
  grid-template-columns: repeat(7, 0fr);
  row-gap: 10px;
  column-gap: 10px;
  margin: 0 auto;
}

.day-item {
  position: relative;
  width: calc((var(--calendar-width) - 60px) / 7);
  height: calc((var(--calendar-width) - 60px) / 7);
  line-height: calc((var(--calendar-width) - 60px) / 7);
  border-radius: 50%;
  text-align: center;
  font-size: 14px;
  color: var(--text-color);
  &.future {
    opacity: 0.2;
  }
  &.today {
    background: var(--main-color);
    color: var(--card-border-color);
    .dot {
      background: var(--card-border-color);
    }
  }
}

.day-item.selected {
  background: #2563eb;
  background: var(--card-border-color);
}

.day-item.inRange {
  background: #dbeafe;
  color: #2563eb;
  border-radius: 0;
}

.day-item.empty {
  color: transparent;
}

.dot {
  position: absolute;
  bottom: 5px;
  left: 50%;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--main-light-color);
  transform: translateX(-50%);
}

.today-dot {
  bottom: 3px;
  color: #2563eb;
  font-size: 10px;
}
</style>
